﻿using Exiled.API.Features;
using Exiled.API.Features.Pools;
using GameCore;
using MapEditorReborn.API.Features.Objects;
using MEC;
using PlayerRoles;
using RemoteAdmin;
using RgCore.Modules;
using RgCore.PlayerHud;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using RgCore.GameModes.Commands.GameModeCommands;
using RgCore.Modules.Commands.SubPluginManagerCommands;
using UnityEngine;
using YamlDotNet.Serialization;
using Log = Exiled.API.Features.Log;

namespace RgCore.GameModes
{
    #region 小游戏废案

        public class RNGGenerator
    {
        public static int GetIntFromSeededString(string seed, int count, int offset, int amount)
        {
            string seedGen = "";
            for (int s = 0; s < count; s++)
            {
                int indexer = (amount * count) + s;
                while (indexer >= seed.Length)
                    indexer -= seed.Length - 1;
                seedGen += seed[indexer].ToString();
            }

            return int.Parse(seedGen);
        }

        public static byte[] GetRandomBytes()
        {
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            byte[] rand = new byte[8];
            rng.GetBytes(rand);
            return rand;
        }

        public static byte[] TextToBytes(string inputText)
        {
            byte[] rand = Encoding.ASCII.GetBytes(inputText);
            return rand;
        }

        public static string GetSeed(byte[] seed)
        {

            var sha = SHA256.Create();
            byte[] bytes = sha.ComputeHash(seed); // System.Text.Encoding.ASCII.GetBytes(seed));

            string newSeed = "";
            foreach (byte bytemap in bytes)
            {
                newSeed += bytemap.ToString();
            }

            return newSeed;
        }

        public static int GetRandomNumber(int minValue, int maxValue)
        {
            using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
            {
                byte[] randomNumber = new byte[4];
                rng.GetBytes(randomNumber);

                int number = BitConverter.ToInt32(randomNumber, 0);

                if (minValue == maxValue)
                {
                    return minValue;
                }

                number = Math.Abs(number % (maxValue - minValue + 1));
                number += minValue;

                return number;
            }
        }
    }
    public class MapInfo
    {
        public string MapName { get; set; }
        public Vector3 Position { get; set; } = new Vector3(6f, 1030f, -43.5f);
        public Vector3 Rotation { get; set; } = Vector3.zero;
        [YamlIgnore]
        public Quaternion MapRotation
        {
            get
            {
                return Quaternion.Euler(Rotation);
            }
            set
            {
                Rotation = value.eulerAngles;
            }
        }
        public Vector3 Scale { get; set; } = Vector3.one;
        public bool IsStatic { get; set; } = true;
        [YamlIgnore]
        public SchematicObject Map { get; set; }
        [YamlIgnore]
        public bool SpawnAutomatically { get; set; } = true;
        public MapInfo() { }
        public MapInfo(string mapName, Vector3 position, Vector3? rotation = null, Vector3? scale = null, bool? isStatic = true)
        {
            MapName = mapName;
            Position = position;
            Scale = scale ?? Vector3.one;
            Rotation = rotation ?? Vector3.zero;
            IsStatic = isStatic.GetValueOrDefault(true);
        }
    }

    #endregion

    public interface IGameModePluginManager
    {
         string[] Plugins { get; }
         GameModePluginStorage PluginStorage { get; }
    }

    public enum GameModePluginStorage : byte
    {
        Whitelist,
        Blacklist,
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class GameModeAttribute : Attribute, IName
    {
        public GameModeAttribute(string gameMode, string description)
        {
            Name = gameMode;
            Description = description;
        }

        public string Name { get; }
        public string Description { get; }

        /// <summary>
        /// 最小玩家数，0代表不限制
        /// </summary>
        public int MinPlayerNeeded { get; set; } = 0;

        /// <summary>
        /// 最大玩家数，0代表不限制
        /// </summary>
        public int MaxPlayerLimit { get; set; } = 0;

        /// <summary>
        /// 允许在当前模式中使用投票，默认为true（管理员不受限）
        /// </summary>
        public bool VotingAllowed { get; set; } = true;

        /// <summary>
        /// 管理限定，玩家不可自主启动此模式
        /// </summary>
        public bool AdminOnly { get; set; } = false;

        /// <summary>
        /// 允许使用角色预留，默认为false
        /// </summary>
        public bool RoleReservationEnabled { get; set; } = false;

        /// <summary>
        /// 启用计分，默认为false，请自行在游戏模式类中实现分数添加
        /// </summary>
        public bool ScoreEnabled { get; set; } = false;
    }

    public abstract class GameMode
    {
        protected GameMode()
        {
        }

        public static event Action<GameMode> ChangingNewGameMode;

        public static Type[] AllGameModes
        {
            get
            {
                var list = ListPool<Type>.Pool.Get(Manager.AllTypes.Keys);
                list.Add(typeof(Normal));
                var array = list.ToArray();
                ListPool<Type>.Pool.Return(list);
                return array;
            }
        }

        public static SubPluginManager<GameModeAttribute> Manager { get; private set; }
        public static SubPluginManagerCommand<GameModeAttribute> Command { get; private set; }
        public static Type DefaultMode { get; protected set; } = typeof(Normal);
        public GameModeAttribute Attribute => GetType().GetCustomAttribute<GameModeAttribute>();
        public static GameMode CurrentGameMode { get; protected set; }
        public static Type NextGameMode { get; protected set; }
        public virtual MapInfo MapInfo { get; protected set; }

        public abstract string GetSpawnQueue();

        public abstract IEnumerable<RoleTypeId> GetScpDrawPool(int scp_count);

        public static void SetNextGameMode(Type mode)
        {
            if (NextGameMode == mode)
                return;
            NextGameMode = mode;
            HudHandler.SendFormattedMsg("game", "<color=#FF1493>游戏模式</color>",
                $"下一回合游戏模式已被设定为：<color=yellow>{mode.GetCustomAttribute<GameModeAttribute>().Name}</color>", 5,
                MsgType.Announcement, ScreenLocation.CenterTop, false, Player.List.ToArray());
        }

        protected virtual void InitializeGame()
        {
            if (this is IGameModePluginManager pluginManager)
            {
                for (int i = ModuleManager.Plugins.Count - 1; i>=0; i--)
                {
                    var plugin = ModuleManager.Plugins[i];
                    if (!plugin.Instance.CanUnload)
                    {
                        continue;
                    }
                    
                    if (pluginManager.PluginStorage == GameModePluginStorage.Blacklist && pluginManager.Plugins.Contains(plugin.Instance.Id))
                    {
                        ModuleManager.DisablePlugin(plugin.Instance.Id,false);
                    }
                    else if (pluginManager.PluginStorage == GameModePluginStorage.Whitelist && !pluginManager.Plugins.Contains(plugin.Instance.Id))
                    {
                        ModuleManager.DisablePlugin(plugin.Instance.Id,false);
                    }
                }
            }
        }

        protected virtual void EndGame()
        {
            if (this is IGameModePluginManager pluginManager)
            {
                for (int i = ModuleManager.DisabledPlugins.Count - 1; i>=0; i--)
                {
                    var plugin = ModuleManager.DisabledPlugins[i];
                    if (pluginManager.PluginStorage == GameModePluginStorage.Blacklist && pluginManager.Plugins.Contains(plugin.Instance.Id))
                    {
                        ModuleManager.EnablePlugin(plugin.Instance.Id,false);
                    }
                    else if (pluginManager.PluginStorage == GameModePluginStorage.Whitelist && !pluginManager.Plugins.Contains(plugin.Instance.Id))
                    {
                        ModuleManager.EnablePlugin(plugin.Instance.Id,false);
                    }
                }
            }
        }

        protected virtual void ReplayGame()
        {
        }

        protected virtual void OnLoaded()
        {
        }



        public static void Active(bool enabled)
        {
            CurrentGameMode = (GameMode)Activator.CreateInstance(DefaultMode);
            CurrentGameMode.InitializeGame();
            if (enabled)
            {
                Manager = new SubPluginManager<GameModeAttribute>("游戏模式", "GameModes", typeof(GameMode));
                Manager.LoadObjects();
                foreach (var item in AllGameModes)
                {
                    GameMode gm = (GameMode)Activator.CreateInstance(item);
                    gm.OnLoaded();
                }
                Command = new SubPluginManagerCommand<GameModeAttribute>("gm", Manager);
                CommandProcessor.RemoteAdminCommandHandler.RegisterCommand(Command);
                CommandProcessor.RemoteAdminCommandHandler.RegisterCommand(new GameModeCommand());
                Exiled.Events.Handlers.Server.RestartingRound.Subscribe(RestartingRound);
            }
        }

        public static IEnumerator<float> RestartingRound()
        {
            if (CurrentGameMode.GetType() == NextGameMode)
            {
                Log.Info("【游戏模式】游戏模式不改变：" + CurrentGameMode.Attribute.Name);
                CurrentGameMode.ReplayGame();
                yield break;
            }
            CurrentGameMode.EndGame();
            CurrentGameMode = (GameMode)Activator.CreateInstance(NextGameMode ?? DefaultMode);
            Log.Info("【游戏模式】游戏模式已被更改为：" + CurrentGameMode.Attribute.Name);
            CurrentGameMode.InitializeGame();
            NextGameMode = null;
            yield break;
        }
    }

    [GameMode("普通", "普通模式，没啥新奇的。", RoleReservationEnabled = true, ScoreEnabled = true)]
    public class Normal : GameMode
    {
        private CoroutineHandle Coroutine;

        public override IEnumerable<RoleTypeId> GetScpDrawPool(int scp_count)
        {
            List<RoleTypeId> allscps = new List<RoleTypeId>
            { RoleTypeId.Scp049, RoleTypeId.Scp079, RoleTypeId.Scp096, RoleTypeId.Scp106, RoleTypeId.Scp173, RoleTypeId.Scp939};
            if (ModuleManager.IsLoaded("CustomCharacter"))
            {
                allscps.Add(RoleTypeId.Scp3114);
            }
            if (scp_count == 1)
            {
                allscps.Remove(RoleTypeId.Scp096);
                allscps.Remove(RoleTypeId.Scp079);
            }
            else if (scp_count < 6)
            {
                allscps.Remove(UnityEngine.Random.Range(0, 2) == 1 ? RoleTypeId.Scp079 : RoleTypeId.Scp096);
            }
            return allscps;
        }

        public override string GetSpawnQueue()
        {
            return ConfigFile.ServerConfig.GetString("team_respawn_queue", "4014314031441404134041434414");
        }

        public IEnumerator<float> Update()
        {
            while (true)
            {
                int minute = RgCore.instance.Config.SystemWarheadMinute;
                if (minute > 0 && Round.IsStarted && Round.ElapsedTime.TotalMinutes >= minute && !Warhead.IsLocked)
                {
                    if (!Warhead.IsInProgress)
                        Warhead.Start();
                    Warhead.IsLocked = true;
                    foreach (Player player in Player.List)
                    {
                        player.SendFormattedMsg("alphawarhead", "<color=#FF4040>系统核弹</color>", "系统核弹已启动", 5, MsgType.Announcement, ScreenLocation.CenterTop, false);
                    }
                }
                yield return Timing.WaitForSeconds(1f);
            }
        }

        protected override void EndGame()
        {
            Normal_Score.SetEnabled(false);
            Timing.KillCoroutines(Coroutine);
        }

        protected override void InitializeGame()
        {
            Coroutine = Timing.RunCoroutine(Update());
            Normal_Score.SetEnabled(true);
        }
    }
}